package com.xy.xyaicpzs.jt.jtdlt;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xy.xyaicpzs.domain.entity.*;
import com.xy.xyaicpzs.domain.vo.DLTFourthStepResultVO;
import com.xy.xyaicpzs.mapper.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 精推大乐透第四步算法分析
 */
@Slf4j
@Component
public class FollowBackendBallAnalysis {
    
    @Autowired
    private D10Mapper d10Mapper;
    
    @Autowired
    private D11Mapper d11Mapper;
    
    @Autowired
    private D6Mapper d6Mapper;
    
    @Autowired
    private D7Mapper d7Mapper;
    
    @Autowired
    private DltBackendHistoryTopMapper dltBackendHistoryTopMapper;
    
    @Autowired
    private DltBackendHistoryTop100Mapper dltBackendHistoryTop100Mapper;
    
    /**
     * 球号和系数的关联类
     */
    @Data
    public static class BallWithCoefficient {
        private Integer ballNumber;
        private Double coefficient;
        private Integer masterBallNumber; // 主球号，用于标识来源

        public BallWithCoefficient(Integer ballNumber, Double coefficient, Integer masterBallNumber) {
            this.ballNumber = ballNumber;
            this.coefficient = coefficient;
            this.masterBallNumber = masterBallNumber;
        }
    }
    
    /**
     * 精推大乐透第四步算法主方法
     * @param level 位置级别（H-高位/M-中位/L-低位）
     * @param previousFrontBalls 上期前区5个球号
     * @param previousBackBalls 上期后区2个球号
     * @param currentFrontBalls 本期前区5个球号
     * @param currentBackFirstBall 本期后区首球号码
     * @return 分析结果
     */
    public DLTFourthStepResultVO analyze(String level, List<Integer> previousFrontBalls, 
                                         List<Integer> previousBackBalls, List<Integer> currentFrontBalls,
                                         Integer currentBackFirstBall) {
        // 参数验证
        validateInputParams(level, previousFrontBalls, previousBackBalls, currentFrontBalls, currentBackFirstBall);
        
        log.info("开始精推大乐透第四步分析，策略：{}，上期前区：{}，上期后区：{}，本期前区：{}，本期后区首球：{}", 
                level, previousFrontBalls, previousBackBalls, currentFrontBalls, currentBackFirstBall);
        
        // 用于存储所有候选球号和对应的系数
        Map<Integer, List<BallWithCoefficient>> ballCoefficientMap = new HashMap<>();
        List<Integer> allCandidateBalls = new ArrayList<>();
        
        // Step 1: 根据5个上期前区球号从D10表获取候选球（取前10个）
        for (Integer previousFrontBall : previousFrontBalls) {
            List<BallWithCoefficient> ballsWithCoefficients = getD10BallsByLevel(previousFrontBall, level);
            for (BallWithCoefficient ball : ballsWithCoefficients) {
                ballCoefficientMap.computeIfAbsent(ball.getBallNumber(), k -> new ArrayList<>()).add(ball);
                allCandidateBalls.add(ball.getBallNumber());
            }
        }
        
        // Step 2: 从dlt_backend_history_top取平均值向上连续2个球号
        List<Integer> top2HistoryTop = getTop2FromDltBackendHistoryTopByAvg();
        allCandidateBalls.addAll(top2HistoryTop);
        
        // Step 3: 从dlt_backend_history_top_100取平均值向上连续2个球号
        List<Integer> top2HistoryTop100 = getTop2FromDltBackendHistoryTop100ByAvg();
        allCandidateBalls.addAll(top2HistoryTop100);
        
        // Step 4: 根据2个上期后区球号从D11表获取候选球（取前10个）
        for (Integer previousBackBall : previousBackBalls) {
            List<BallWithCoefficient> ballsWithCoefficients = getD11BallsByLevel(previousBackBall, level);
            for (BallWithCoefficient ball : ballsWithCoefficients) {
                ballCoefficientMap.computeIfAbsent(ball.getBallNumber(), k -> new ArrayList<>()).add(ball);
                allCandidateBalls.add(ball.getBallNumber());
            }
        }
        
        // Step 5: 根据5个本期前区球号从D6表获取候选球（取前10个）
        for (Integer currentFrontBall : currentFrontBalls) {
            List<BallWithCoefficient> ballsWithCoefficients = getD6BallsByLevel(currentFrontBall, level);
            for (BallWithCoefficient ball : ballsWithCoefficients) {
                ballCoefficientMap.computeIfAbsent(ball.getBallNumber(), k -> new ArrayList<>()).add(ball);
                allCandidateBalls.add(ball.getBallNumber());
            }
        }
        
        // Step 6: 根据1个本期后区首球从D7表获取候选球（根据策略取不同数量）
        List<BallWithCoefficient> ballsFromD7 = getD7BallsByLevel(currentBackFirstBall, level);
        for (BallWithCoefficient ball : ballsFromD7) {
            ballCoefficientMap.computeIfAbsent(ball.getBallNumber(), k -> new ArrayList<>()).add(ball);
            allCandidateBalls.add(ball.getBallNumber());
        }
        
        // Step 7: 统计分析并生成结果
        List<DLTFourthStepResultVO.BallAnalysisResult> results = analyzeResults(allCandidateBalls, ballCoefficientMap);
        
        return DLTFourthStepResultVO.builder()
                .results(results)
                .strategy(level)
                .previousFrontBalls(previousFrontBalls)
                .previousBackBalls(previousBackBalls)
                .currentFrontBalls(currentFrontBalls)
                .currentBackFirstBall(currentBackFirstBall)
                .build();
    }
    
    /**
     * 根据级别从D10表获取候选球号和系数（取前10个，如果第10个系数相同则一并加入）
     */
    private List<BallWithCoefficient> getD10BallsByLevel(Integer masterBallNumber, String level) {
        List<D10> d10List = d10Mapper.selectList(
            new QueryWrapper<D10>()
                .eq("masterBallNumber", masterBallNumber)
                .orderByDesc("coefficient"));
        
        if (CollectionUtils.isEmpty(d10List)) {
            log.warn("D10表中主球{}没有数据", masterBallNumber);
            return new ArrayList<>();
        }
        
        // 所有策略都取前10个，如果第10个系数相同则一并加入
        List<BallWithCoefficient> result = new ArrayList<>();
        
        if (d10List.size() <= 10) {
            // 如果总数不超过10个，全部加入
            for (D10 d10 : d10List) {
                result.add(new BallWithCoefficient(d10.getSlaveBallNumber(), d10.getCoefficient(), masterBallNumber));
            }
            return result;
        }
        
        // 先加入前10个
        for (int i = 0; i < 10; i++) {
            D10 d10 = d10List.get(i);
            result.add(new BallWithCoefficient(d10.getSlaveBallNumber(), d10.getCoefficient(), masterBallNumber));
        }
        
        // 获取第10个球号的系数
        Double boundaryCoefficient = d10List.get(9).getCoefficient();
        
        // 继续查找后面系数相同的球号
        for (int i = 10; i < d10List.size(); i++) {
            D10 d10 = d10List.get(i);
            if (d10.getCoefficient().equals(boundaryCoefficient)) {
                result.add(new BallWithCoefficient(d10.getSlaveBallNumber(), d10.getCoefficient(), masterBallNumber));
            } else {
                break; // 系数不同，停止查找
            }
        }
        
        return result;
    }
    
    /**
     * 根据级别从D11表获取候选球号和系数（取前10个，如果第10个系数相同则一并加入）
     */
    private List<BallWithCoefficient> getD11BallsByLevel(Integer masterBallNumber, String level) {
        List<D11> d11List = d11Mapper.selectList(
            new QueryWrapper<D11>()
                .eq("masterBallNumber", masterBallNumber)
                .orderByDesc("coefficient"));
        
        if (CollectionUtils.isEmpty(d11List)) {
            log.warn("D11表中主球{}没有数据", masterBallNumber);
            return new ArrayList<>();
        }
        
        // 所有策略都取前10个，如果第10个系数相同则一并加入
        List<BallWithCoefficient> result = new ArrayList<>();
        
        if (d11List.size() <= 10) {
            // 如果总数不超过10个，全部加入
            for (D11 d11 : d11List) {
                result.add(new BallWithCoefficient(d11.getSlaveBallNumber(), d11.getCoefficient(), masterBallNumber));
            }
            return result;
        }
        
        // 先加入前10个
        for (int i = 0; i < 10; i++) {
            D11 d11 = d11List.get(i);
            result.add(new BallWithCoefficient(d11.getSlaveBallNumber(), d11.getCoefficient(), masterBallNumber));
        }
        
        // 获取第10个球号的系数
        Double boundaryCoefficient = d11List.get(9).getCoefficient();
        
        // 继续查找后面系数相同的球号
        for (int i = 10; i < d11List.size(); i++) {
            D11 d11 = d11List.get(i);
            if (d11.getCoefficient().equals(boundaryCoefficient)) {
                result.add(new BallWithCoefficient(d11.getSlaveBallNumber(), d11.getCoefficient(), masterBallNumber));
            } else {
                break; // 系数不同，停止查找
            }
        }
        
        return result;
    }
    
    /**
     * 根据级别从D6表获取候选球号和系数（取前10个，如果第10个系数相同则一并加入）
     */
    private List<BallWithCoefficient> getD6BallsByLevel(Integer masterBallNumber, String level) {
        List<D6> d6List = d6Mapper.selectList(
            new QueryWrapper<D6>()
                .eq("masterBallNumber", masterBallNumber)
                .orderByDesc("coefficient"));
        
        if (CollectionUtils.isEmpty(d6List)) {
            log.warn("D6表中主球{}没有数据", masterBallNumber);
            return new ArrayList<>();
        }
        
        // 所有策略都取前10个，如果第10个系数相同则一并加入
        List<BallWithCoefficient> result = new ArrayList<>();
        
        if (d6List.size() <= 10) {
            // 如果总数不超过10个，全部加入
            for (D6 d6 : d6List) {
                result.add(new BallWithCoefficient(d6.getSlaveBallNumber(), d6.getCoefficient(), masterBallNumber));
            }
            return result;
        }
        
        // 先加入前10个
        for (int i = 0; i < 10; i++) {
            D6 d6 = d6List.get(i);
            result.add(new BallWithCoefficient(d6.getSlaveBallNumber(), d6.getCoefficient(), masterBallNumber));
        }
        
        // 获取第10个球号的系数
        Double boundaryCoefficient = d6List.get(9).getCoefficient();
        
        // 继续查找后面系数相同的球号
        for (int i = 10; i < d6List.size(); i++) {
            D6 d6 = d6List.get(i);
            if (d6.getCoefficient().equals(boundaryCoefficient)) {
                result.add(new BallWithCoefficient(d6.getSlaveBallNumber(), d6.getCoefficient(), masterBallNumber));
            } else {
                break; // 系数不同，停止查找
            }
        }
        
        return result;
    }
    
    /**
     * 根据级别从D7表获取候选球号和系数
     */
    private List<BallWithCoefficient> getD7BallsByLevel(Integer masterBallNumber, String level) {
        List<D7> d7List = d7Mapper.selectList(
            new QueryWrapper<D7>()
                .eq("masterBallNumber", masterBallNumber)
                .orderByDesc("coefficient"));
        
        if (CollectionUtils.isEmpty(d7List)) {
            log.warn("D7表中主球{}没有数据", masterBallNumber);
            return new ArrayList<>();
        }
        
        if ("H".equalsIgnoreCase(level)) {
            return getHighLevelBallsFromD7(d7List, masterBallNumber);
        } else if ("M".equalsIgnoreCase(level)) {
            return getMiddleLevelBallsFromD7(d7List, masterBallNumber);
        } else { // L
            return getLowLevelBallsFromD7(d7List, masterBallNumber);
        }
    }
    
    /**
     * 高位策略：从D7表获取系数最大的前5个球号（如果第5个系数相同则一并加入）
     */
    private List<BallWithCoefficient> getHighLevelBallsFromD7(List<D7> d7List, Integer masterBallNumber) {
        List<BallWithCoefficient> result = new ArrayList<>();
        
        if (d7List.size() <= 5) {
            // 如果总数不超过5个，全部加入
            for (D7 d7 : d7List) {
                result.add(new BallWithCoefficient(d7.getSlaveBallNumber(), d7.getCoefficient(), masterBallNumber));
            }
            return result;
        }
        
        // 先加入前5个
        for (int i = 0; i < 5; i++) {
            D7 d7 = d7List.get(i);
            result.add(new BallWithCoefficient(d7.getSlaveBallNumber(), d7.getCoefficient(), masterBallNumber));
        }
        
        // 获取第5个球号的系数
        Double boundaryCoefficient = d7List.get(4).getCoefficient();
        
        // 继续查找后面系数相同的球号
        for (int i = 5; i < d7List.size(); i++) {
            D7 d7 = d7List.get(i);
            if (d7.getCoefficient().equals(boundaryCoefficient)) {
                result.add(new BallWithCoefficient(d7.getSlaveBallNumber(), d7.getCoefficient(), masterBallNumber));
            } else {
                break; // 系数不同，停止查找
            }
        }
        
        return result;
    }
    
    /**
     * 中位策略：从D7表获取平均值附近的5个球号（向上2个，向下2个，边界系数相同则一并加入）
     */
    private List<BallWithCoefficient> getMiddleLevelBallsFromD7(List<D7> d7List, Integer masterBallNumber) {
        if (d7List.size() < 5) {
            log.warn("D7表数据不足5条，实际{}条", d7List.size());
            List<BallWithCoefficient> result = new ArrayList<>();
            for (D7 d7 : d7List) {
                result.add(new BallWithCoefficient(d7.getSlaveBallNumber(), d7.getCoefficient(), masterBallNumber));
            }
            return result;
        }
        
        // 计算平均系数（保留两位小数，截断方式）
        double avgCoefficient = d7List.stream()
                .mapToDouble(D7::getCoefficient)
                .average()
                .orElse(0.0);
        // 截断到两位小数
        avgCoefficient = Math.floor(avgCoefficient * 100) / 100;
        
        // 找到第一个比平均值大的位置（从下到上遍历）
        int avgPosition = -1;
        for (int i = d7List.size() - 1; i >= 0; i--) {
            if (d7List.get(i).getCoefficient() >= avgCoefficient) {
                avgPosition = i;
                break;
            }
        }
        
        if (avgPosition == -1) {
            avgPosition = 0; // 如果没找到，取第一个
        }
        
        List<BallWithCoefficient> result = new ArrayList<>();
        
        // 先加入平均值位置的球号
        result.add(new BallWithCoefficient(d7List.get(avgPosition).getSlaveBallNumber(), 
                d7List.get(avgPosition).getCoefficient(), masterBallNumber));
        
        // 向上取2个球号，处理边界系数相同情况
        int upCount = 0;
        Double upBoundaryCoeff = null;
        for (int i = avgPosition - 1; i >= 0 && upCount < 2; i--) {
            result.add(new BallWithCoefficient(d7List.get(i).getSlaveBallNumber(), 
                    d7List.get(i).getCoefficient(), masterBallNumber));
            upCount++;
            if (upCount == 2) {
                upBoundaryCoeff = d7List.get(i).getCoefficient();
            }
        }
        
        // 向上边界处理：继续添加与第2个球号系数相同的球号
        if (upBoundaryCoeff != null) {
            for (int i = avgPosition - 3; i >= 0; i--) {
                if (d7List.get(i).getCoefficient().equals(upBoundaryCoeff)) {
                    result.add(new BallWithCoefficient(d7List.get(i).getSlaveBallNumber(), 
                            d7List.get(i).getCoefficient(), masterBallNumber));
                } else {
                    break;
                }
            }
        }
        
        // 向下取2个球号，处理边界系数相同情况
        int downCount = 0;
        Double downBoundaryCoeff = null;
        for (int i = avgPosition + 1; i < d7List.size() && downCount < 2; i++) {
            result.add(new BallWithCoefficient(d7List.get(i).getSlaveBallNumber(), 
                    d7List.get(i).getCoefficient(), masterBallNumber));
            downCount++;
            if (downCount == 2) {
                downBoundaryCoeff = d7List.get(i).getCoefficient();
            }
        }
        
        // 向下边界处理：继续添加与第2个球号系数相同的球号
        if (downBoundaryCoeff != null) {
            for (int i = avgPosition + 3; i < d7List.size(); i++) {
                if (d7List.get(i).getCoefficient().equals(downBoundaryCoeff)) {
                    result.add(new BallWithCoefficient(d7List.get(i).getSlaveBallNumber(), 
                            d7List.get(i).getCoefficient(), masterBallNumber));
                } else {
                    break;
                }
            }
        }
        
        return result;
    }
    
    /**
     * 低位策略：从D7表获取最小值向上5个球号（含最小值，第1个系数相同则一并加入）
     */
    private List<BallWithCoefficient> getLowLevelBallsFromD7(List<D7> d7List, Integer masterBallNumber) {
        if (d7List.size() < 5) {
            log.warn("D7表数据不足5条，实际{}条", d7List.size());
            List<BallWithCoefficient> result = new ArrayList<>();
            for (D7 d7 : d7List) {
                result.add(new BallWithCoefficient(d7.getSlaveBallNumber(), d7.getCoefficient(), masterBallNumber));
            }
            return result;
        }
        
        // 从最小值开始向上取5个（d7List已按系数降序排列，最后5个就是最小的）
        List<BallWithCoefficient> result = new ArrayList<>();
        int startIndex = Math.max(0, d7List.size() - 5);
        
        // 先加入基本的5个球号
        for (int i = startIndex; i < d7List.size(); i++) {
            D7 d7 = d7List.get(i);
            result.add(new BallWithCoefficient(d7.getSlaveBallNumber(), d7.getCoefficient(), masterBallNumber));
        }
        
        // 处理第1个球号（系数最大的）边界相同情况
        if (startIndex > 0) {
            Double firstBallCoeff = d7List.get(startIndex).getCoefficient();
            
            // 继续向前查找系数相同的球号
            for (int i = startIndex - 1; i >= 0; i--) {
                if (d7List.get(i).getCoefficient().equals(firstBallCoeff)) {
                    result.add(new BallWithCoefficient(d7List.get(i).getSlaveBallNumber(), 
                            d7List.get(i).getCoefficient(), masterBallNumber));
                } else {
                    break; // 系数不同，停止查找
                }
            }
        }
        
        return result;
    }
    
    /**
     * 从dlt_backend_history_top取平均值向上连续2个球号（按系数排行，处理边界相同系数）
     */
    private List<Integer> getTop2FromDltBackendHistoryTopByAvg() {
        List<DltBackendHistoryTop> allHistoryTopList = dltBackendHistoryTopMapper.selectList(
            new QueryWrapper<DltBackendHistoryTop>()
                .orderByDesc("activeCoefficient"));
        
        if (CollectionUtils.isEmpty(allHistoryTopList)) {
            return new ArrayList<>();
        }
        
        // 计算平均系数（保留两位小数，截断方式）
        final double avgCoefficient = Math.floor(allHistoryTopList.stream()
                .mapToDouble(DltBackendHistoryTop::getActiveCoefficient)
                .average()
                .orElse(0.0) * 100) / 100;
        
        // 筛选出大于或等于平均值的球，并按差值排序
        List<DltBackendHistoryTop> aboveAvgBalls = allHistoryTopList.stream()
                .filter(ball -> ball.getActiveCoefficient() >= avgCoefficient)
                .sorted(Comparator.comparingDouble(ball -> ball.getActiveCoefficient() - avgCoefficient))
                .collect(Collectors.toList());
        
        // 如果没有大于或等于平均值的球号，返回空列表
        if (aboveAvgBalls.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 逐层添加球号，直到达到2个或更多（相同差值的要一起加入）
        List<Integer> result = new ArrayList<>();
        double currentDiff = -1;
        
        for (DltBackendHistoryTop ball : aboveAvgBalls) {
            double diff = ball.getActiveCoefficient() - avgCoefficient;
            
            // 如果已经有2个球了，且当前差值与之前不同，则停止
            if (result.size() >= 2 && diff != currentDiff) {
                break;
            }
            
            result.add(ball.getBallNumber());
            currentDiff = diff;
        }
        
        return result;
    }
    
    /**
     * 从dlt_backend_history_top_100取平均值向上连续2个球号（按系数排行，处理边界相同系数）
     */
    private List<Integer> getTop2FromDltBackendHistoryTop100ByAvg() {
        List<DltBackendHistoryTop100> allHistoryTop100List = dltBackendHistoryTop100Mapper.selectList(
            new QueryWrapper<DltBackendHistoryTop100>()
                .orderByDesc("activeCoefficient"));
        
        if (CollectionUtils.isEmpty(allHistoryTop100List)) {
            return new ArrayList<>();
        }
        
        // 计算平均系数（保留两位小数，截断方式）
        final double avgCoefficient = Math.floor(allHistoryTop100List.stream()
                .mapToDouble(DltBackendHistoryTop100::getActiveCoefficient)
                .average()
                .orElse(0.0) * 100) / 100;
        
        // 筛选出大于或等于平均值的球，并按差值排序
        List<DltBackendHistoryTop100> aboveAvgBalls = allHistoryTop100List.stream()
                .filter(ball -> ball.getActiveCoefficient() >= avgCoefficient)
                .sorted(Comparator.comparingDouble(ball -> ball.getActiveCoefficient() - avgCoefficient))
                .collect(Collectors.toList());
        
        // 如果没有大于或等于平均值的球号，返回空列表
        if (aboveAvgBalls.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 逐层添加球号，直到达到2个或更多（相同差值的要一起加入）
        List<Integer> result = new ArrayList<>();
        double currentDiff = -1;
        
        for (DltBackendHistoryTop100 ball : aboveAvgBalls) {
            double diff = ball.getActiveCoefficient() - avgCoefficient;
            
            // 如果已经有2个球了，且当前差值与之前不同，则停止
            if (result.size() >= 2 && diff != currentDiff) {
                break;
            }
            
            result.add(ball.getBallNumber());
            currentDiff = diff;
        }
        
        // 如果结果球号数量 > 2，通过dlt_backend_history_top表筛选
        if (result.size() > 2) {
            return selectTop2FromDltBackendHistoryTop(result);
        }
        
        return result;
    }
    
    /**
     * 从dlt_backend_history_top表中选择前2个球号
     */
    private List<Integer> selectTop2FromDltBackendHistoryTop(List<Integer> candidateBalls) {
        // 获取候选球号在dlt_backend_history_top表中的活跃系数
        Map<Integer, Double> ballCoefficientMap = new HashMap<>();
        for (Integer ballNumber : candidateBalls) {
            DltBackendHistoryTop record = dltBackendHistoryTopMapper.selectOne(
                new QueryWrapper<DltBackendHistoryTop>()
                    .eq("ballNumber", ballNumber));
            double coefficient = (record != null) ? record.getActiveCoefficient() : 0.0;
            ballCoefficientMap.put(ballNumber, coefficient);
        }
        
        // 按活跃系数降序排序，选择前2个
        List<Map.Entry<Integer, Double>> sortedEntries = ballCoefficientMap.entrySet().stream()
                .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
                .collect(Collectors.toList());
        
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < Math.min(2, sortedEntries.size()); i++) {
            result.add(sortedEntries.get(i).getKey());
        }
        
        return result;
    }
    
    /**
     * 统计分析并生成结果
     */
    private List<DLTFourthStepResultVO.BallAnalysisResult> analyzeResults(
            List<Integer> allCandidateBalls, 
            Map<Integer, List<BallWithCoefficient>> ballCoefficientMap) {
        
        // 统计球号出现次数
        Map<Integer, Integer> ballFrequencyMap = new HashMap<>();
        for (Integer ball : allCandidateBalls) {
            ballFrequencyMap.put(ball, ballFrequencyMap.getOrDefault(ball, 0) + 1);
        }
        
        // 计算系数和
        Map<Integer, Double> ballCoefficientSumMap = new HashMap<>();
        for (Map.Entry<Integer, List<BallWithCoefficient>> entry : ballCoefficientMap.entrySet()) {
            Integer ballNumber = entry.getKey();
            List<BallWithCoefficient> coefficients = entry.getValue();
            double sum = coefficients.stream()
                    .mapToDouble(BallWithCoefficient::getCoefficient)
                    .sum();
            ballCoefficientSumMap.put(ballNumber, sum);
        }
        
        // 获取所有有排行数据的球号（包括频次为0的球号）
        Set<Integer> allBallsWithRanking = getAllBallsWithRanking();
        
        // 获取百期排位和历史排位
        Map<Integer, Integer> top100RankingMap = getTop100Rankings(allBallsWithRanking);
        Map<Integer, Integer> historyRankingMap = getHistoryRankings(allBallsWithRanking);
        
        // 组装结果
        List<DLTFourthStepResultVO.BallAnalysisResult> results = new ArrayList<>();
        for (Integer ballNumber : allBallsWithRanking) {
            DLTFourthStepResultVO.BallAnalysisResult result = DLTFourthStepResultVO.BallAnalysisResult.builder()
                    .ballNumber(ballNumber)
                    .frequency(ballFrequencyMap.getOrDefault(ballNumber, 0))
                    .coefficientSum(ballCoefficientSumMap.getOrDefault(ballNumber, 0.0))
                    .top100Ranking(top100RankingMap.get(ballNumber))
                    .historyRanking(historyRankingMap.get(ballNumber))
                    .build();
            results.add(result);
        }
        
        // 按出现次数降序排列，次数相同的按球号升序排列
        results.sort((a, b) -> {
            int frequencyCompare = b.getFrequency().compareTo(a.getFrequency());
            if (frequencyCompare != 0) {
                return frequencyCompare;
            }
            return a.getBallNumber().compareTo(b.getBallNumber());
        });
        
        return results;
    }
    
    /**
     * 获取所有有排行数据的球号（包括频次为0的球号）
     */
    private Set<Integer> getAllBallsWithRanking() {
        Set<Integer> allBalls = new HashSet<>();
        
        // 从DLT后区百期排行表获取所有球号
        List<DltBackendHistoryTop100> top100List = dltBackendHistoryTop100Mapper.selectList(
            new QueryWrapper<DltBackendHistoryTop100>());
        for (DltBackendHistoryTop100 item : top100List) {
            allBalls.add(item.getBallNumber());
        }
        
        // 从DLT后区历史排行表获取所有球号
        List<DltBackendHistoryTop> historyTopList = dltBackendHistoryTopMapper.selectList(
            new QueryWrapper<DltBackendHistoryTop>());
        for (DltBackendHistoryTop item : historyTopList) {
            allBalls.add(item.getBallNumber());
        }
        
        return allBalls;
    }
    
    /**
     * 获取球号在百期排行表中的排位
     */
    private Map<Integer, Integer> getTop100Rankings(Set<Integer> ballNumbers) {
        Map<Integer, Integer> result = new HashMap<>();
        
        // 直接查询指定球号的排行数据，使用表中的ranking字段作为排名
        List<DltBackendHistoryTop100> top100List = dltBackendHistoryTop100Mapper.selectList(
            new QueryWrapper<DltBackendHistoryTop100>()
                .in("ballNumber", ballNumbers));
        
        // 使用表中的ranking字段作为排名
        for (DltBackendHistoryTop100 item : top100List) {
            result.put(item.getBallNumber(), item.getRanking());
        }
        
        // 对于没有在百期排行表中的球号，设置为null
        for (Integer ballNumber : ballNumbers) {
            if (!result.containsKey(ballNumber)) {
                result.put(ballNumber, null);
            }
        }
        
        return result;
    }
    
    /**
     * 获取球号在历史排行表中的排位
     */
    private Map<Integer, Integer> getHistoryRankings(Set<Integer> ballNumbers) {
        Map<Integer, Integer> result = new HashMap<>();
        
        // 直接查询指定球号的排行数据，使用表中的ranking字段作为排名
        List<DltBackendHistoryTop> historyTopList = dltBackendHistoryTopMapper.selectList(
            new QueryWrapper<DltBackendHistoryTop>()
                .in("ballNumber", ballNumbers));
        
        // 使用表中的ranking字段作为排名
        for (DltBackendHistoryTop item : historyTopList) {
            result.put(item.getBallNumber(), item.getRanking());
        }
        
        // 对于没有在历史排行表中的球号，设置为null
        for (Integer ballNumber : ballNumbers) {
            if (!result.containsKey(ballNumber)) {
                result.put(ballNumber, null);
            }
        }
        
        return result;
    }
    
    /**
     * 参数验证
     */
    private void validateInputParams(String level, List<Integer> previousFrontBalls, 
                                    List<Integer> previousBackBalls, List<Integer> currentFrontBalls,
                                    Integer currentBackFirstBall) {
        if (!"H".equalsIgnoreCase(level) && !"M".equalsIgnoreCase(level) && !"L".equalsIgnoreCase(level)) {
            throw new IllegalArgumentException("位置级别必须是H/M/L之一");
        }
        
        if (CollectionUtils.isEmpty(previousFrontBalls) || previousFrontBalls.size() != 5) {
            throw new IllegalArgumentException("上期前区球号必须为5个");
        }
        
        if (CollectionUtils.isEmpty(previousBackBalls) || previousBackBalls.size() != 2) {
            throw new IllegalArgumentException("上期后区球号必须为2个");
        }
        
        if (CollectionUtils.isEmpty(currentFrontBalls) || currentFrontBalls.size() != 5) {
            throw new IllegalArgumentException("本期前区球号必须为5个");
        }
        
        if (currentBackFirstBall == null || currentBackFirstBall < 1 || currentBackFirstBall > 12) {
            throw new IllegalArgumentException("本期后区首球号码范围应为1-12");
        }
        
        for (Integer frontBall : previousFrontBalls) {
            if (frontBall < 1 || frontBall > 35) {
                throw new IllegalArgumentException("上期前区球号范围应为1-35");
            }
        }
        
        for (Integer backBall : previousBackBalls) {
            if (backBall < 1 || backBall > 12) {
                throw new IllegalArgumentException("上期后区球号范围应为1-12");
            }
        }
        
        for (Integer frontBall : currentFrontBalls) {
            if (frontBall < 1 || frontBall > 35) {
                throw new IllegalArgumentException("本期前区球号范围应为1-35");
            }
        }
    }
}
